Understanding the Structure Type

Now that you understand the role of enumeration types, let's examine the use of .NET structures (or simply structs). Structure types are well suited for modeling mathematical, geometrical, and other "atomic" entities in your application. A structure (like an enumeration) is a user-defined type; however, structures are not simply a collection of name/value pairs. Rather, structures are types that can contain any number of data fields and members that operate on these fields.

Note If you have a background in OOP, you can think of a structure as a "lightweight class type," given that structures provide a way to define a type that supports encapsulation, but cannot be used to build a family of related types. When you need to build a family of related types through inheritance, you will need to make use of class types.

On the surface, the process of defining and using structures is very simple, but as they say, the devil is in the details. To begin understanding the basics of structure types, create a new project named FunWithStructures. In C#, structures are created using the struct keyword. Define a new structure named Point, which defines two member variables of type int and a set of methods to interact with said data:

struct Point
{
    // Fields of the structure.
    public int X;
    public int Y;

    // Add 1 to the (X, Y) position.
    public void Increment()
    {
        X++; Y++;
    }

    // Subtract 1 from the (X, Y) position.
    public void Decrement()
    {
        X--; Y--;
    }

    // Display the current position.
    public void Display()
    {
        Console.WriteLine("X = {0}, Y = {1}", X, Y);
    }
}

Here, you have defined your two integer fields (X and Y) using the public keyword, which is an access control modifier. Declaring data with the public keyword ensures the caller has direct access to the data from a given Point variable (via the dot operator).

Note It is typically considered bad style to define public data within a class or structure. Rather, you will want to define private data, which can be accessed and changed using public properties.

Here is a Main() method that takes our Point type out for a test drive:

static void Main(string[] args)
{
    Console.WriteLine("***** A First Look at Structures *****\n");
    // Create an initial Point.
    Point myPoint;
    myPoint.X = 349;
    myPoint.Y = 76;
    myPoint.Display();

    // Adjust the X and Y values.
    myPoint.Increment();
    myPoint.Display();
    Console.ReadLine();
}

The output is as you would expect:

***** A First Look at Structures *****

X = 349, Y = 76
X = 350, Y = 77

Creating Structure Variables

When you wish to create a structure variable, you have a variety of options. Here, you simply create a Point variable and assign each piece of public field data before invoking its members. If you do not assign each piece of public field data (X and Y in our case) before making use of the structure, you will receive a compiler error:

// Error! Did not assign Y value.
Point p1;
p1.X = 10;
p1.Display();

// OK! Both fields assigned before use.
Point p2;
p2.X = 10;
p2.Y = 10;
p2.Display();

As an alternative, we can create structure variables using the C# new keyword, which will invoke the structure's default constructor. By definition, a default constructor does not take any arguments. The benefit of invoking the default constructor of a structure is that each piece of field data is automatically set to its default value:

// Set all fields to default values
// using the default constructor.
Point p1 = new Point();

// Prints X=0,Y=0
p1.Display();

It is also possible to design a structure with a custom constructor. This allows you to specify the values of field data upon variable creation, rather than having to set each data member field by field. To illustrate, update the Point structure with the following code:

struct Point
{
    // Fields of the structure.
    public int X;
    public int Y;

    // A custom constructor.
    public Point(int XPos, int YPos)
    {
        X = XPos;
        Y = YPos;
    }
...
}

With this, we could now create Point variables as follows:

// Call custom constructor.
Point p2 = new Point(50, 60);

// Prints X=50,Y=60
p2.Display();

As mentioned, working with structures on the surface is quite simple. However, to deepen your understanding of this type, you need to explore the distinction between a .NET value type and a .NET reference type.